import 'dart:typed_data';
import 'package:bluetooth_parse_plugin/src/base/message_base.dart';
import 'package:flutter/widgets.dart';
import 'package:bluetooth_parse_plugin/src/base/crypto_base.dart';

// 解析加密
class LxParse {
  // 加密表的长度
  static const int _cryptoTableLength = 256;

  // 加密 randCryptKey 随机索引
  static Uint8List encrypt<T extends LxCryptoBase, M extends MessageBase>(
    T crypto,
    M message, [
    int randCryptKey = -1,
  ]) {
    Uint8List bytes = message.toBytes();
    // 加解密过程相同
    if (crypto.needPrint == true) {
      debugPrint("加密前: $bytes");
    }
    _encrypt2decrypt(crypto, bytes, randCryptKey);
    if (crypto.escapeByte != null && crypto.needEscapeBytes != null) {
      // 对需要转义的字节进行转义处理
      Set<int> escapeSet = crypto.needEscapeBytes!.toSet();
      int escapeByteValue = crypto.escapeByte!;
      int additionalLength =
          bytes.where((byte) => escapeSet.contains(byte)).length;
      if (additionalLength > 0) {
        List<int> temp = List.filled(bytes.length + additionalLength, 0);
        int index = 0;
        for (var byte in bytes) {
          if (escapeSet.contains(byte)) {
            temp[index++] = escapeByteValue;
          }
          temp[index++] = byte;
        }
        bytes
          ..clear()
          ..addAll(temp);
      }
    }
    if (crypto.needPrint == true) {
      debugPrint("加密后: $bytes");
    }
    return bytes;
  }

  // 解密 randCryptKey 随机索引
  static Uint8List decrypt<T extends LxCryptoBase, M extends MessageBase>(
    T crypto,
    M message, [
    int randCryptKey = -1,
  ]) {
    Uint8List bytes = message.toBytes();
    // 加解密过程相同
    if (crypto.needPrint == true) {
      debugPrint("解密前: $bytes");
    }
    _encrypt2decrypt(crypto, bytes, randCryptKey);
    if (crypto.escapeByte != null) {
      // 去转义
      List<int> temp = [];
      bool es = false;
      for (var i = 0; i < bytes.length; i++) {
        if (es) {
          temp.add(bytes[i]);
          es = false;
        } else {
          if (bytes[i] != crypto.escapeByte) {
            temp.add(bytes[i]);
          } else {
            es = true;
          }
        }
      }
      bytes
        ..clear()
        ..addAll(temp);
    }

    if (crypto.needPrint == true) {
      debugPrint("解密后: $bytes");
    }
    return bytes;
  }

  // 是否显示日志信息
  static void showLoger<T extends LxCryptoBase>(T crypto, {bool show = true}) {
    crypto.needPrint = show;
  }

  // 加密 randCryptKey 随机索引
  static void _encrypt2decrypt<T extends LxCryptoBase>(
    T crypto,
    Uint8List bytes, [
    int randCryptKey = -1,
  ]) {
    bool shouldEncrypt = _needEncrypt(crypto);
    if (crypto.needPrint == true) {
      debugPrint("是否加密：$shouldEncrypt");
    }
    // 是否需要加密
    if (!shouldEncrypt) return;
    // 随机码
    if (crypto.randCryptKeyIndex != null) {
      if (crypto.randCryptKeyIndex! >= 0 &&
          crypto.randCryptKeyIndex! < bytes.length) {
        randCryptKey = bytes[crypto.randCryptKeyIndex!];
      } else {
        throw RangeError('randCryptKeyIndex is out of bounds');
      }
    }
    // 加解密
    if (crypto.notCryptoPrefixLength != null &&
        crypto.notCryptoSuffixLength != null &&
        crypto.randCryptKeyIndex != null &&
        crypto.cryptoTable != null) {
      int tempRandCryptKey = randCryptKey;
      for (int i = crypto.notCryptoPrefixLength!;
          i < bytes.length - crypto.notCryptoSuffixLength!;
          i++) {
        // 掐头去尾，加密中间段
        tempRandCryptKey %= _cryptoTableLength;
        bytes[i] = bytes[i] ^ crypto.cryptoTable![tempRandCryptKey++];
      }
    }
  }

  // 是否需要加密
  static bool _needEncrypt<T extends LxCryptoBase>(T crypto) {
    return crypto.needCrypto &&
        (crypto.cryptoTable?.length ?? 0) == _cryptoTableLength &&
        crypto.cryptoTable != null &&
        crypto.randCryptKeyIndex != null;
  }
}
